package cz.vutbr.feec.utko.mtin.regression;

import cz.vutbr.feec.utko.ef.core.Config;
import cz.vutbr.feec.utko.ef.core.GProgram;
import cz.vutbr.feec.utko.ef.evolution.DefaultEvolutionSpecifierTree;
import cz.vutbr.feec.utko.ef.evolution.DisplayType;
import cz.vutbr.feec.utko.ef.evolution.IEvolutionSpecifier;
import cz.vutbr.feec.utko.ef.gp.tree.TreeChromozome;
import cz.vutbr.feec.utko.ef.grammar.Grammar;
import cz.vutbr.feec.utko.ef.grammar.Rule;
import cz.vutbr.feec.utko.ef.individuals.ActionTree;

public class RegressionTest {

	public static void main(String[] args) {
		// Grammar
		Grammar g = new Grammar();

		// Grammar definition
		// The Root node can evolve to E node
		g.addRule("ROOT", new Rule("E"));

		// The E node can evolve to E + E or to E - E or to E* E
		// or to E / E, or to one of the input parameters
		g.addRule("E",
		// E -> E + E
				new Rule(new PlusAction(), "E", "E"),
				// E -> E - E
				new Rule(new MinusAction(), "E", "E"),
				// E -> E * E
				new Rule(new TimesAction(), "E", "E"),
				// E -> E / E
				new Rule(new DivisionAction(), "E", "E"),
				// E -> number
				new Rule("INPUT_R1"),
				// E -> number
				new Rule("INPUT_R2"),
				// E -> number
				new Rule("INPUT_I1"),
				// E -> number
				new Rule("INPUT_I2"));

		// Creating of input parameters and their registration
		ActionTree R1 = new R1();
		g.addRule("INPUT_R1", new Rule(R1));
		g.registerInputParameter(R1);

		ActionTree R2 = new R2();
		g.addRule("INPUT_R2", new Rule(R2));
		g.registerInputParameter(R2);

		ActionTree I1 = new I1();
		g.addRule("INPUT_I1", new Rule(I1));
		g.registerInputParameter(I1);

		ActionTree I2 = new I2();
		g.addRule("INPUT_I2", new Rule(I2));
		g.registerInputParameter(I2);

		// Making of training set according to measured values
		double[][] values = new double[12][5];

		values[0][0] = 40.0;
		values[0][1] = 10.0;
		values[0][2] = 0.250;
		values[0][3] = 1.000;
		values[0][4] = 8.000;

		values[1][0] = 5.0;
		values[1][1] = 5.0;
		values[1][2] = 2.000;
		values[1][3] = 2.000;
		values[1][4] = 2.500;

		values[2][0] = 10.0;
		values[2][1] = 40.0;
		values[2][2] = 1.000;
		values[2][3] = 0.2500;
		values[2][4] = 8.000;

		values[3][0] = 6.0;
		values[3][1] = 4.0;
		values[3][2] = 1.666;
		values[3][3] = 2.500;
		values[3][4] = 2.400;

		values[4][0] = 4.0;
		values[4][1] = 8.0;
		values[4][2] = 2.500;
		values[4][3] = 1.250;
		values[4][4] = 2.666;

		values[5][0] = 1.0;
		values[5][1] = 4.0;
		values[5][2] = 10.000;
		values[5][3] = 2.500;
		values[5][4] = 0.800;

		values[6][0] = 20.0;
		values[6][1] = 20.0;
		values[6][2] = 0.500;
		values[6][3] = 0.500;
		values[6][4] = 10.000;

		values[7][0] = 5.0;
		values[7][1] = 20.0;
		values[7][2] = 2.000;
		values[7][3] = 0.500;
		values[7][4] = 4.000;

		values[8][0] = 4.0;
		values[8][1] = 6.0;
		values[8][2] = 2.500;
		values[8][3] = 1.666;
		values[8][4] = 2.400;

		values[9][0] = 8.0;
		values[9][1] = 12.0;
		values[9][2] = 1.250;
		values[9][3] = 0.833;
		values[9][4] = 4.800;

		values[10][0] = 40.0;
		values[10][1] = 10.0;
		values[10][2] = 0.250;
		values[10][3] = 1.000;
		values[10][4] = 8.000;

		values[11][0] = 15.0;
		values[11][1] = 5.0;
		values[11][2] = 0.666;
		values[11][3] = 2.000;
		values[11][4] = 3.750;

		// Creating new instance of fitness function
		FitnessRegression fitness = new FitnessRegression();
		fitness.addValueVector(values);

		// Creating new instance of configuration file
		Config cfg = new Config("config_default.ini");

		// Creating new evolution specifier
		IEvolutionSpecifier s = new DefaultEvolutionSpecifierTree(cfg, fitness,
				g);
		
		// Creating new instance of genetic program
		GProgram gp = new GProgram(cfg, s);
		
		// Genetic program run
		gp.evolve();
		
		// Finding the best chromosome
		TreeChromozome ch = (TreeChromozome) gp.getPopulation()
				.getBestIndividual();

		// Setting up parameters for visualization of chromosome (svg file),
		// this configuration does not work every time, depends on GraphViz,
		// on the end of program is given the output for GraphViz too
		ch.visualize("chromozome.gif", DisplayType.BRIEF);
		
		// The fitness function is given to the output
		System.out.println("Fitness: " + ch.getCachedFitness());
		System.out.println();
		// The code for visualization for GraphViz
		System.out.println(ch.getCodeToVisualizer());
	}
}
